#include <QList>
#include "QNmea0183Package.h"
#include <QDebug>

QNmea0183Package::QNmea0183Package(const QByteArray &data)
{
    fromRaw(data);
}

void QNmea0183Package::fromRaw(const QByteArray &data)
{
    _type = Invalid;
    QList<QByteArray> parts = data.split(',');
    if(parts.at(0).size() > 6)
        return;

    // trimme the checksum data
    QByteArray lastPart = parts.takeLast();
    int index = lastPart.indexOf('*');
    if(index < 0)
        return;
    parts.append(lastPart.left(index));

    QByteArray typeStr = parts.at(0);
    if(typeStr.isEmpty())
        return;
    if(typeStr.at(0) == '$')
        typeStr = typeStr.mid(3);
    int partCount = parts.count();
    if((typeStr == "GGA") && (partCount == 15))
    {
        //$GPGGA,061831.000,2236.9152,N,11403.2422,E,2,07,1.1,144.0,M,-2.2,M,4.8,0000*60
        _type = GGA;
        // 061831.000, hhmmss.sss
        const QByteArray &utcTimeStr = parts.at(1);
        // 2236.9152, ddmm.mmmm
        const QByteArray &latitudeStr = parts.at(2);
        // 11403.2422, dddmm.mmm
        const QByteArray &longitudeStr = parts.at(4);

        GGAPackage &ggaInfo = _pkgBody.ggaInfo;
        ggaInfo.utcTime.hour = utcTimeStr.mid(0, 2).toUInt();
        ggaInfo.utcTime.minute = utcTimeStr.mid(2, 2).toUInt();
        ggaInfo.utcTime.second = utcTimeStr.mid(4, 2).toUInt();
        ggaInfo.utcTime.msecond = utcTimeStr.mid(7).toUInt();
        strncpy(ggaInfo.rawLatitude, latitudeStr.constData(),
                sizeof(ggaInfo.rawLatitude) - 1);
        strncpy(ggaInfo.rawLongitude, longitudeStr.constData(),
                sizeof(ggaInfo.rawLongitude) - 1);
#if 1
        ggaInfo.latitude = double(latitudeStr.left(2).toUInt())
                + (double(latitudeStr.mid(2, 2).toUInt()) / 60.00)
                + (double(latitudeStr.mid(5).toUInt()) / 600000.00);
        ggaInfo.longitude = double(longitudeStr.left(3).toUInt())
                + (double(longitudeStr.mid(3, 2).toUInt()) / 60.00)
                + (double(longitudeStr.mid(6).toUInt()) / 600000.00);
#else
        ggaInfo.latitude = double(latitudeStr.left(2).toUInt())
                + double(latitudeStr.mid(2).toDouble() / 60.00);
        ggaInfo.longitude = double(longitudeStr.left(3).toUInt())
                + double(longitudeStr.mid(3).toDouble() / 60.00);
#endif
        ggaInfo.nsFlag = parts.at(3).isEmpty() ? ' ' : parts.at(3).at(0);
        ggaInfo.ewFlag = parts.at(5).isEmpty() ? ' ' : parts.at(5).at(0);
        ggaInfo.flag = parts.at(6).toUInt();
        ggaInfo.satelliteNum = parts.at(7).toUInt();
        ggaInfo.hdop = parts.at(8).toFloat();
        ggaInfo.radioAltitude = parts.at(9).toFloat();
        ggaInfo.groundAltitude = parts.at(11).toFloat();
    }
    else if((typeStr == "GSA") && (partCount == 18))
    {
        // $GPGSA,A,3,18,22,25,12,14,21,24,15,,,,,1.93,1.04,1.63*01
        _type = GSA;
        GSAPackage &gsaInfo = _pkgBody.gsaInfo;
        gsaInfo.maMode = parts.at(1).isEmpty() ? ' ' : parts.at(1).at(0);
        gsaInfo.mode = parts.at(2).toUInt();
        for(int i = 0; i < 12; i++)
        {
            gsaInfo.radioNum[i] = parts.at(3 + i).toUInt();
        }
        gsaInfo.pdop = parts.at(15).toFloat();
        gsaInfo.hdop = parts.at(16).toFloat();
        gsaInfo.vdop = parts.at(17).toFloat();
    }
    // 数量为4的整数倍
    else if((typeStr == "GSV") && ((partCount & 0x03) == 0))
    {
        // $GPGSV,3,1,11,12,40,089,45,14,37,314,46,15,10,078,44,18,77,096,43*72
        // $GPGSV,3,2,11,21,27,192,31,22,60,330,43,24,24,037,45,25,42,142,41*71
        // $GPGSV,3,3,11,31,21,230,27,42,51,128,37,50,46,122,39*4D
        _type = GSV;
        GSVPackage &gsvInfo = _pkgBody.gsvInfo;
        gsvInfo.msgCount = parts.at(1).toUInt();
        gsvInfo.msgIndex = parts.at(2).toUInt();
        gsvInfo.satelliteNum = parts.at(3).toUInt();
        int idx = 0;
        for(int i = 4; i < parts.count(); i += 4)
        {
            gsvInfo.satellites[idx].satId = parts.at(i).toUInt();
            gsvInfo.satellites[idx].angleOfElevation = parts.at(i + 1).toUInt();
            gsvInfo.satellites[idx].angleOfDirection = parts.at(i + 2).toUInt();
            gsvInfo.satellites[idx].cNo = parts.at(i + 3).toUInt();
            idx++;
        }
        for(; idx < 4; idx++)
        {
            gsvInfo.satellites[idx].satId = -1;
            gsvInfo.satellites[idx].angleOfElevation = -1;
            gsvInfo.satellites[idx].angleOfDirection = -1;
            gsvInfo.satellites[idx].cNo = -1;
        }
    }
    else if((typeStr == "RMC") && (partCount == 13))
    {
        // $GPRMC,061831.000,A,2236.9152,N,11403.2422,E,0.00,,130214,,,D*76
        _type = RMC;
        // 061831.000, hhmmss.sss
        const QByteArray &utcTimeStr = parts.at(1);
        // 2236.9152, ddmm.mmmm
        const QByteArray &latitudeStr = parts.at(3);
        // 11403.2422, dddmm.mmm
        const QByteArray &longitudeStr = parts.at(5);
        // 130214, ddmmyy
        const QByteArray &dateStr = parts.at(9);

        RMCPackage &rmcInfo = _pkgBody.rmcInfo;
        rmcInfo.flag = parts.at(2).at(0);
        rmcInfo.utcTime.hour = utcTimeStr.mid(0, 2).toUInt();
        rmcInfo.utcTime.minute = utcTimeStr.mid(2, 2).toUInt();
        rmcInfo.utcTime.second = utcTimeStr.mid(4, 2).toUInt();
        rmcInfo.utcTime.msecond = utcTimeStr.mid(7).toUInt();
        strncpy(rmcInfo.rawLatitude, latitudeStr.constData(),
                sizeof(rmcInfo.rawLatitude) - 1);
        strncpy(rmcInfo.rawLongitude, longitudeStr.constData(),
                sizeof(rmcInfo.rawLongitude) - 1);
#if 1
        rmcInfo.latitude = double(latitudeStr.left(2).toUInt())
                + (double(latitudeStr.mid(2, 2).toUInt()) / 60.00)
                + (double(latitudeStr.mid(5).toUInt()) / 600000.00);
        rmcInfo.longitude = double(longitudeStr.left(3).toUInt())
                + (double(longitudeStr.mid(3, 2).toUInt()) / 60.00)
                + (double(longitudeStr.mid(6).toUInt()) / 600000.00);
#else
        rmcInfo.latitude = double(latitudeStr.left(2).toUInt())
                + double(latitudeStr.mid(2).toDouble() / 60.00);
        rmcInfo.longitude = double(longitudeStr.left(3).toUInt())
                + double(longitudeStr.mid(3).toDouble() / 60.00);
#endif
        rmcInfo.nsFlag = parts.at(4).isEmpty() ? ' ' : parts.at(4).at(0);
        rmcInfo.ewFlag = parts.at(6).isEmpty() ? ' ' : parts.at(6).at(0);
        rmcInfo.speed = parts.at(7).toFloat();
        rmcInfo.direction = parts.at(8).toFloat();
        rmcInfo.utcDate.day = dateStr.mid(0, 2).toUInt();
        rmcInfo.utcDate.month = dateStr.mid(2, 2).toUInt();
        rmcInfo.utcDate.year = dateStr.mid(4, 2).toUInt() + 2000;
    }
    else if((typeStr == "VTG") && ((partCount == 9) || (partCount == 10)))
    {
        _type = VTG;
        VTGPackage &vtgInfo = _pkgBody.vtgInfo;
        vtgInfo.directionT = parts.at(1).toFloat();
        vtgInfo.directionM = parts.at(3).toFloat();
        vtgInfo.speed = parts.at(5).toFloat();
        vtgInfo.speedKMH = parts.at(7).toFloat();
        if(partCount == 10)
            vtgInfo.modeFlag = parts.at(9).isEmpty() ? ' ' : parts.at(9).at(0);
    }
}
